﻿#pragma once
/**
 * @简介：封装json，使之更像js对象，支持连续索引，与range-for
 * 结合reflection可方便的进行数据解析。
 * @author：rayzhang
 * @协作：
 * @其他
 * @性能优化：考虑减少内存拷贝和递归次数。
 * @todo: 支持string迭代器
 */
#pragma once
#include <QDebug>
#include <QMap>
#include <QString>
#include <QVariant>
#include <memory>
#include <stdexcept>
#include <string>
#include <utility>
#include <variant>
#include "../reflection/reflection.hpp"
#include "../libflow_global.h"
namespace flow
{
// JsonValue
class LIBFLOW_API Json final
{
    class Parser;
    class Token;

public:
    // token type
    enum class Type
    {
        Null,
        Bool,
        Int,
        Double,
        String,
        Array,
        Object
    };
    // 数据类型可以在这里改。
    using Null   = std::nullptr_t;
    using Bool   = bool;
    using Int    = qsizetype;
    using Double = double;
    using String = QString;
    using Array  = QVector<Json>;
    using Object = QMap<String, Json>; // QMap<QString,
    // using Data = QVariant;
    using Data = std::variant<Null, Bool, Double, Int, String, Array, Object>;
    // 兼容 nlohuman::json
    using parse_error = std::exception;

    class iterator
    {
    public:
        using ArrayIterator    = QVector<Json>::iterator;
        using ObjectIterator   = QMap<QString, Json>::iterator;
        using iterator_concept = std::bidirectional_iterator_tag;
        iterator(const ArrayIterator& it)
            : it(std::in_place_type<ArrayIterator>, it)
            , _type(Type::Array)
        { }

        iterator(const ObjectIterator& it)
            : it(std::in_place_type<ObjectIterator>, it)
            , _type(Type::Object)
        { }

        Json& operator*() const
        {
            if (_type == Type::Object) {
                return **std::get_if<ObjectIterator>(&it);
            }
            return **std::get_if<ArrayIterator>(&it);
        }

        iterator& operator++()
        {
            if (_type == Type::Object) {
                ++(std::get<ObjectIterator>(it));
            }
            else {
                ++(std::get<ArrayIterator>(it));
            }
            return *this;
        }
        iterator& operator--()
        {
            if (_type == Type::Object) {
                --(std::get<ObjectIterator>(it));
            }
            else {
                --(std::get<ArrayIterator>(it));
            }
            return *this;
        }
        bool operator!=(const iterator& other) const
        {
            if (_type != other._type) {
                throw std::logic_error("Cannot compare iterators of different types");
            }
            if (_type == Type::Object) {
                return *std::get<ObjectIterator>(it) != *std::get<ObjectIterator>(other.it);
            }
            return *std::get<ArrayIterator>(it) != *std::get<ArrayIterator>(other.it);
        }

        qsizetype operator-(const iterator& other) const
        {
            if (_type != other._type) {
                throw std::logic_error("Cannot subtract iterators of different types");
            }
            if (_type == Type::Array) {
                return std::get<ArrayIterator>(it) - std::get<ArrayIterator>(other.it);
            }
            throw std::logic_error("Cannot subtract Object::iterator");
        }

        iterator operator++(int)
        {
            iterator old = *this;
            operator++();
            return old;
        }
        iterator operator--(int)
        {
            iterator old = *this;
            operator--();
            return old;
        }

    private:
        std::variant<ArrayIterator, ObjectIterator> it;
        Type _type{Type::Null};
    };
    // todo：实现const_iterator
    class const_iterator
    {
    public:
        using ArrayIterator  = QVector<Json>::const_iterator;
        using ObjectIterator = QMap<QString, Json>::const_iterator;

        const_iterator(const ArrayIterator& it)
            : it(std::in_place_type<ArrayIterator>, it)
            , _type(Type::Array)
        { }

        const_iterator(const ObjectIterator& it)
            : it(std::in_place_type<ObjectIterator>, it)
            , _type(Type::Object)
        { }

        const Json& operator*() const
        {
            if (_type == Type::Object) {
                return **std::get_if<ObjectIterator>(&it);
            }
            return **std::get_if<ArrayIterator>(&it);
        }

        bool operator!=(const const_iterator& other) const
        {
            if (_type != other._type) {
                throw std::logic_error("Cannot compare iterators of different types");
            }
            if (_type == Type::Object) {
                return *std::get<ObjectIterator>(it) != *std::get<ObjectIterator>(other.it);
            }
            return *std::get<ArrayIterator>(it) != *std::get<ArrayIterator>(other.it);
        }

        qsizetype operator-(const const_iterator& other) const
        {
            if (_type != other._type) {
                throw std::logic_error("Cannot subtract iterators of different types");
            }
            if (_type == Type::Array) {
                return std::get<ArrayIterator>(it) - std::get<ArrayIterator>(other.it);
            }
            throw std::logic_error("Cannot subtract Object::iterator");
        }

        const_iterator& operator++()
        {
            if (_type == Type::Object) {
                ++(std::get<ObjectIterator>(it));
            }
            else {
                ++(std::get<ArrayIterator>(it));
            }
            return *this;
        }
        const_iterator& operator--()
        {
            if (_type == Type::Object) {
                --(std::get<ObjectIterator>(it));
            }
            else {
                --(std::get<ArrayIterator>(it));
            }
            return *this;
        }
        const_iterator operator++(int)
        {
            const_iterator old = *this;
            operator++();
            return old;
        }
        const_iterator operator--(int)
        {
            const_iterator old = *this;
            operator--();
            return old;
        }

    private:
        std::variant<ArrayIterator, ObjectIterator> it;
        Type _type{Type::Null};
    };

    // 构造
    Json(Type t = Type::Null);
    Json(Type t, const Data& d);

    Json(Bool d)
        : Json(Type::Bool, d)
    { }

    Json(Int d)
        : Json(Type::Int, d)
    { }

    Json(int d)
        : Json(Type::Int, static_cast<Int>(d))
    { }

    Json(Double d)
        : Json(Type::Double, d)
    { }

    Json(const Array& d)
        : Json(Type::Array, d)
    { }

    Json(const Object& d)
        : Json(Type::Object, d)
    { }

    Json(const std::string_view str)
        : Json(Type::String, str.data())
    { }

    Json(const String& str)
        : Json(Type::String, str)
    { }

    Json(const char* str)
        : Json(Type::String, str)
    { }
    // 扩展
    Json(const QStringList& stringList);
    // 拷贝构造
    Json(const Json& d);
    ~Json() = default;
    // 移动构造
    Json(Json&& other) noexcept
        : type_(other.type_)
        , data_(std::move(other.data_))
    {
        other.type_ = Type::Null;
    }

    // 移动赋值
    Json& operator=(Json&& other) noexcept
    {
        swap(other);
        return *this;
    }

    Json& operator=(const int& value) { return *this = Json(value); }
    Json& operator=(const Int& value) { return *this = Json(value); }
    Json& operator=(const double& value) { return *this = Json(value); }
    Json& operator=(const Bool& value) { return *this = Json(value); }
    Json& operator=(const char* str) { return *this = Json(str); }
    Json& operator=(const Array& value) { return *this = Json(value); }
    Json& operator=(const Object& value) { return *this = Json(value); }
    Json& operator=(const Json& other) = default;
    // 助手函数
    static Json array() { return {Type::Array}; }
    static Json object() { return {Type::Object}; }
    // 解析
    static Json parse(const String& str, int* errorCode = nullptr, std::function<void(int)> progressCallback = {});
    static Json parse(const QByteArray& str, int* errorCode = nullptr, std::function<void(int)> progressCallback = {});
    static Json parse(const char* str, int* errorCode = nullptr, std::function<void(int)> progressCallback = {});
    static Json parseFile(const QString& filename, int* errorCode = nullptr, std::function<void(int)> progressCallback = {});
    bool saveToFile(const QString& filename, int* errorCode = nullptr) const;
    QString stringify() const { return dump(); }
    String dump(bool compact = true) const; // 未实现格式化

    // 类型
    [[nodiscard]] Type type() const { return type_; }
    // 获取值
    [[nodiscard]] bool isNull() const { return type() == Type::Null; }
    [[nodiscard]] bool isBool() const { return type() == Type::Bool; }
    [[nodiscard]] bool isDouble() const { return type() == Type::Double; }
    [[nodiscard]] bool isInt() const { return type() == Type::Int; }
    [[nodiscard]] bool isString() const { return type() == Type::String; }
    [[nodiscard]] bool isArray() const { return type() == Type::Array; }
    [[nodiscard]] bool isObject() const { return type() == Type::Object; }
    // template<typename T>
    // requires is_any_of<T, Null, Bool, Int, Double, String, Array, Object>
    // bool isType() const {
    //     // 判断当前的variant是否存储了指定的类型
    //     return std::holds_alternative<T>(data_);
    // }
    //[[nodiscard]] bool isUndefined() const { return type() == Type::Undefined; }

    bool toBool(bool defaultValue = false) const;
    Int toInt(Int defaultValue = 0) const;
    double toDouble(double defaultValue = 0) const;
    String toString(const String& defaultValue = "") const;
    std::string toStdString(const QString& defaultValue = "") const;
    Array toArray(const Array& defaultValue = Array()) const;
    Object toObject(const Object& defaultValue = Object()) const;

    template <typename T>
    const T to() const
        requires flow::reflection::is_reflection_v<T>;
    template <typename T>
    bool to(QVector<T>& listT) const;

    // 比较
    bool operator==(const Json& other) const;
    bool operator==(const qsizetype other) const;
    bool operator==(const int other) const;
    bool operator==(const double other) const;
    bool operator==(const QString& other) const;
    bool operator==(const QChar& other) const;
    bool operator!=(const Json& other) const;
    Json& operator/=(double value);
    // 获取数据
    template <typename... Args>
    [[nodiscard]] bool contains(const QString& key, const Args&... args) const;
    // 获取或设置数据
    Json& operator[](const String& key);
    Json& operator[](const std::string_view& key);
    Json& operator[](const char* key);         // object key
    Json& operator[](const int i);             // array index
    Json operator[](const QString& key) const; // array index
    Json operator[](const char* key) const;    // object key
    Json at(const int i) const;                // array index

    template <typename T>
    Json valueOr(const char* key, T t = {}) const;
    // 返回存在的第一个值
    template <typename... Args>
    Json value(std::string_view, Args... args) const;
    template <typename K, typename... Args>
    Json value(const K& key, Args... args) const
        requires std::is_same_v<K, QString>;
    // template <typename... Args>
    // Json value(const QString& key, Args... args) const;

    bool push_back(const Json& other);
    bool push_back(Json&& other);
    bool remove(const String& key);
    bool remove(const int i);
    void clear();

    // 保留用作反射相关
    // template<typename T> T get() { return to }
    // 类型重载，获取数据
    operator Bool() const;
    // operator Null();
    operator Double() const;
    operator Int() const;
    operator int() const;
    operator String() const;
    // operator QByteArray() const;
    operator std::string() const;

    iterator begin() noexcept;
    iterator end() noexcept;
    const_iterator const_begin() const noexcept;
    const_iterator const_end() const noexcept;
    qsizetype size() const noexcept
    {
        if (isString()) {
            return operator String().length();
        }
        if (isArray() || isObject()) {
            return const_end() - const_begin();
        }
        return 0;
    }
    qsizetype length() const noexcept { return size(); }
    bool empty() const noexcept { return size() == 0; }

    void setParseProgressChanged(const std::function<void(int)>& callback);
    // 创建一个新的值
    Json map(const std::function<Json(const Json& v)>& f) const;
    Json filter(const std::function<Json(const Json& v)>& f) const;
    void reserve(qsizetype s);
    Json& insert(const QString& key, const Json& value);

public:
    // 兼容性处理
    [[nodiscard]] bool is_array() const { return type() == Type::Array; }
    [[nodiscard]] bool is_object() const { return type() == Type::Object; }
    [[nodiscard]] bool is_null() const { return type() == Type::Null; }

    // 将Json转为指定类型, 和ORM一样。
private:
    void swap(Json& other) noexcept
    {
        std::swap(this->data_, other.data_);
        std::swap(this->type_, other.type_);
    }

    Json throwError(const std::string_view& message) const;

    template <typename T>
    static void assign(T&& value, const Json& data)
    {
        if (data.isNull()) {
            return;
        }
        using U                   = std::remove_const_t<std::remove_reference_t<T>>;
        constexpr bool is_int64_v = (std::is_same_v<T, int64_t> || std::is_same_v<T, uint64_t>);
        if constexpr (std::is_integral_v<U> && !is_int64_v) {
            value = data.toInt();
        }
        else if constexpr (is_int64_v) {
            value = data.toInt();
        }
        else if constexpr (std::is_floating_point_v<U>) {
            value = data.toDouble();
        }
        else if constexpr (std::is_same_v<std::string, U>) {
            value = data.toString().toStdString();
        }
        else if constexpr (std::is_same_v<QString, U>) {
            value = data.toString();
        }
        else if constexpr (std::is_same_v<QByteArray, U>) {
            value = data.toString().toUtf8();
        }
        else {
            qDebug() << "this type has not supported yet" << Qt::endl;
        }
    }

private:
    Type type_;
    Data data_;
    std::function<void(int)> _parseProgressChanged;
    // std::unique_ptr<Data> data_;
};
// 主模板，对应于一般情况，假定不存在value_type
template <typename, typename = std::void_t<>>
struct has_value_type : std::false_type
{ };

// 特化版本，对应于存在value_type的情况
template <typename T>
struct has_value_type<T, std::void_t<typename T::value_type>> : std::true_type
{ };
template <typename T>
inline const T Json::to() const
    requires flow::reflection::is_reflection_v<T>
{
    T t;
    const auto& object = toObject();
    if (!object.isEmpty()) {
        // 遍历字段
        flow::reflection::for_each(t, [&t, this, &object](auto item, auto i) {
            std::string_view name = flow::reflection::get_name<T>(i);
            if (object.contains(name.data())) {
                auto v         = object.value(name.data());
                using ItemType = std::decay_t<decltype(t.*item)>;
                if (v.isArray()) {
                    // 如果 ItemType 是一个容器
                    if constexpr (has_value_type<ItemType>::value) {
                        using ValueType = typename std::decay_t<decltype(t.*item)>::value_type;
                        if constexpr (flow::reflection::is_reflection_v<ValueType>) {
                            v.to(t.*item);
                        }
                        // 如果是基础类型
                        if constexpr (std::is_arithmetic_v<ValueType>) {
                            for (const auto& d : v) {
                                (t.*item).push_back(d);
                            }
                        }
                    }
                }
                else if (v.isObject()) {
                    if constexpr (flow::reflection::is_reflection_v<ItemType>) {
                        v.to<ItemType>(t.*item);
                    }
                }
                // map
                else {
                    assign(t.*item, v);
                }
            }
        });
    }
    return t;
}

template <typename T>
bool Json::to(QVector<T>& listT) const
{
    const auto arr = toArray();
    for (int row = 0; row < size(); ++row) {
        listT.push_back(arr.at(row).to<T>());
    }
    return !listT.isEmpty();
}

template <typename... Args>
bool Json::contains(const QString& key, const Args&... args) const
{
    if (!isArray() && !isObject() && !isString()) {
        return false;
    }
    if (const Object* obj = std::get_if<Object>(&data_)) {
        if (obj->contains(key)) {
            return true;
        }
        if constexpr (sizeof...(args) > 0) {
            return contains(std::forward<QString>(args)...);
        }
    }
    // String
    else if (const String* str = std::get_if<String>(&data_)) {
        if (str->contains(key)) {
            return true;
        }
        if constexpr (sizeof...(args) > 0) {
            return contains(std::forward<Args>(args)...);
        }
    }
    // Array
    else if (const Array* arr = std::get_if<Array>(&data_)) {
        if (arr->contains(key)) {
            return true;
        }
        if constexpr (sizeof...(args) > 0) {
            return contains(std::forward<Args>(args)...);
        }
    }
    return false;
    // return ((hasValue(args)) || ...);
}

template <typename T>
Json Json::valueOr(const char* key, T t) const
{
    try {
        if (contains(key)) {
            return value(key);
        }
    }
    catch (...) {
    }
    return t;
}

template <typename... Args>
Json Json::value(std::string_view key, Args... args) const
{
    if (contains(key.data())) {
        const auto d = std::get_if<Object>(&data_);
        if (!d) {
            return {};
        }
        return d->value(key.data());
    }
    if constexpr (sizeof...(args) == 0) {
        return {};
    }
    else {
        return value(std::forward<Args>(args)...);
    }
}

template <typename K, typename... Args>
Json Json::value(const K& key, Args... args) const
    requires std::is_same_v<K, QString>
{
    return value(key.toStdString(), std::forward<Args>(args)...);
}

using Value  = Json;
using Let    = Json;
using Object = Json::Object;
using Array  = Json::Array;

using JsonObject = Json::Object;
using JsonArray  = Json::Array;

} // namespace flow
